package tzy.scrollview;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.NestedScrollingParent2;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;


public class CustomNestedScrollView extends MoreChildNestedScrollView implements NestedScrollingParent2 {
    View mHeaderView;
    View mFooterView;
    private OnScrollChangeListener2 mListener;

    /**
     *
     * */
    int mOffsetY;

    public void setOnScrollChangeListener2(OnScrollChangeListener2 listener) {
        this.mListener = listener;
    }

//    View mNestedChildView;
//    int mNestedScrollType;

    public CustomNestedScrollView(Context context) {
        this(context, null);
    }

    public CustomNestedScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ensureChild();
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
        final ViewGroup.LayoutParams lp = child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                getPaddingLeft() + getPaddingRight(), lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                getPaddingTop() + getPaddingBottom(), lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

    @Override
    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {

        if (child == mHeaderView) {
            measureChildWithMarginsUnspecified(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);

        } else if (child == mFooterView) {
            measureChildWithMarginsSpecified(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed + mOffsetY);
        }

    }

    void measureChildWithMarginsUnspecified(View child, int parentWidthMeasureSpec, int widthUsed,
                                            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

    void measureChildWithMarginsSpecified(View child, int parentWidthMeasureSpec, int widthUsed,
                                          int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }


    //    @Override
//    public boolean startNestedScroll(int axes) {
//        if (mNestedChildView != null) {
//            ((NestedScrollingChild) mNestedChildView).stopNestedScroll();
//            mNestedChildView = null;
//            return false;
//        } else {
//
//            boolean dispatch = super.startNestedScroll(axes);
////        if (dispatch&& mNestedChildView != null) {
////            ((RecyclerView) mNestedChildView).stopScroll();
////        }
//            return dispatch;
//        }
//    }
//
//
//    @Override
//    public boolean startNestedScroll(int axes, int type) {
//
//        if (mNestedChildView != null) {
//            ((NestedScrollingChild2) mNestedChildView).stopNestedScroll(mNestedScrollType);
//            mNestedChildView = null;
//            return false;
//        } else {
//            boolean dispatch = super.startNestedScroll(axes, type);
////        if (dispatch&& mNestedChildView != null) {
////            ((RecyclerView) mNestedChildView).stopScroll();
////        }
//            return dispatch;
//        }
//    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
//        if (mNestedChildView != null) {
//            if (mNestedScrollType >= 0) {
//                ((NestedScrollingChild2) mNestedChildView).stopNestedScroll(mNestedScrollType);
//                mNestedChildView = null;
//                mNestedScrollType = -1;
//            } else {
//                ((NestedScrollingChild) mNestedChildView).stopNestedScroll();
//                mNestedChildView = null;
//                mNestedScrollType = -1;
//
//            }
//        }

        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
//        if (mNestedChildView != null) {
//            if (mNestedScrollType >= 0) {
//                ((NestedScrollingChild2) mNestedChildView).stopNestedScroll(mNestedScrollType);
//                mNestedChildView = null;
//                mNestedScrollType = -1;
//            } else {
//                ((NestedScrollingChild) mNestedChildView).stopNestedScroll();
//                mNestedChildView = null;
//                mNestedScrollType = -1;
//
//            }
//        }
        return super.onTouchEvent(ev);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) {
        return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
//        mNestedChildView = target;
        super.onNestedScrollAccepted(child, target, nestedScrollAxes);
    }

    @Override
    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes, int type) {

//        mNestedChildView = target;
//        mNestedScrollType = type;
        mParentHelper.onNestedScrollAccepted(child, target, axes, type);
        startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, type);
    }

    @Override
    public void onStopNestedScroll(@NonNull View target, int type) {
        mParentHelper.onStopNestedScroll(target, type);
        stopNestedScroll(type);
//        mNestedChildView = null;
//        mNestedScrollType = -1;

    }

    @Override
    public void onStopNestedScroll(View target) {
        super.onStopNestedScroll(target);
//        mNestedChildView = null;
//        mNestedScrollType = -1;

    }

    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @Nullable int[] consumed, int type) {

        dispatchNestedPreScroll(dx, dy, consumed, null, type);
        if (dy > 0) {
            final int range = getHeaderScrollRange() - mOffsetY;
            final int oldScrollY = getScrollY();

            overScrollByCompat(0, dy - consumed[1], getScrollX(), oldScrollY, 0, range, 0, 0, false);

            final int scrolledDeltaY = getScrollY() - oldScrollY;
            consumed[1] += scrolledDeltaY;
        }
    }

    @Override
    boolean overScrollByCompat(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        return super.overScrollByCompat(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
    }

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(target, dx, dy, consumed);

        if (dy > 0) {
            final int range = getHeaderScrollRange()-mOffsetY;
            final int oldScrollY = getScrollY();

            overScrollByCompat(0, dy - consumed[1], getScrollX(), oldScrollY, 0, range, 0, 0, false);

            final int scrolledDeltaY = getScrollY() - oldScrollY;
            consumed[1] += scrolledDeltaY;
        }
    }


    @Override
    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        final int oldScrollY = getScrollY();
        scrollBy(0, dyUnconsumed);
        final int myConsumed = getScrollY() - oldScrollY;
        final int myUnconsumed = dyUnconsumed - myConsumed;
        dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null, type);
    }

    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
    }

    public void setOverScrollOffset(int y) {
        mOffsetY = y;
        requestLayout();
    }


    int getHeaderScrollRange() {
        return mHeaderView.getHeight();
    }


    private void ensureChild() {
        if (mHeaderView != null && mFooterView != null)
            return;

        if (getChildCount() != 2) {
            throw new IllegalStateException();
        }
        mHeaderView = getChildAt(0);
        mFooterView = getChildAt(1);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mListener != null) {
            final int topViewAt = getTopViewAt();
            if (topViewAt >= 0) {
                mListener.onScrollChange(this, t, oldt, topViewAt, getChildAt(topViewAt));
            }
        }
    }

    private int getTopViewAt() {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; ++i) {
            if (inChild(getChildAt(i), getPaddingLeft(), getPaddingTop() + mOffsetY)) {
                return i;
            }
        }
        return -1;
    }

    private boolean inChild(View child, int x, int y) {

        final int scrollY = getScrollY();
        return !(y < child.getTop() - scrollY
                || y >= child.getBottom() - scrollY
                || x < child.getLeft()
                || x >= child.getRight());

    }

    public interface OnScrollChangeListener2 {
        void onScrollChange(CustomNestedScrollView v, int scrollY,
                            int oldScrollY, int topViewAt, View topView);
    }
}
